/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package skyproc;

import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
import java.util.zip.DataFormatException;
import lev.LExporter;
import lev.LFlags;
import lev.LStream;
import skyproc.exceptions.BadParameter;
import skyproc.exceptions.BadRecord;

/**
 * Ingredient Records
 * @author Justin Swanson
 */
public class INGR extends MagicItem {

    Type[] types = {Type.INGR};
    SubString MODL = new SubString(Type.MODL, true);
    SubData MODT = new SubData(Type.MODT);
    SubForm YNAM = new SubForm(Type.YNAM);
    SubForm ZNAM = new SubForm(Type.ZNAM);
    DATA DATA = new DATA();
    ENIT ENIT = new ENIT();
    SubString ICON = new SubString(Type.ICON, true);
    SubString MICO = new SubString(Type.MICO, true);
    SubForm ETYP = new SubForm(Type.ETYP);
    /**
     *
     */
    public ScriptPackage scripts = new ScriptPackage();

    INGR() {
	super();
	init();
    }

    @Override
    final void init() {
	super.init();
	subRecords.add(scripts);
	subRecords.add(OBND);
	subRecords.add(FULL);
	subRecords.add(keywords);
	subRecords.add(MODL);
	subRecords.add(MODT);
	subRecords.add(YNAM);
	subRecords.add(ZNAM);
	subRecords.add(DATA);
	subRecords.add(ENIT);
	subRecords.add(magicEffects);
	subRecords.add(ICON);
	subRecords.add(MICO);
	subRecords.add(ETYP);
    }

    @Override
    Type[] getTypes() {
	return types;
    }

    @Override
    Record getNew() {
	return new INGR();
    }

    class DATA extends SubRecord {

	int value = 0;
	float weight = 0;

	DATA () {
	    super(Type.DATA);
	}

	@Override
	void export(LExporter out, Mod srcMod) throws IOException {
	    super.export(out, srcMod);
	    out.write(value);
	    out.write(weight);
	}

	@Override
	void parseData(LStream in) throws BadRecord, DataFormatException, BadParameter, IOException {
	    super.parseData(in);
	    value = in.extractInt(4);
	    weight = in.extractFloat();
	    if (SPGlobal.logging()) {
		logSync("", "Setting DATA:    Weight: " + weight);
	    }
	}

	@Override
	SubRecord getNew(Type type) {
	    return new DATA();
	}

	@Override
	int getContentLength(Mod srcMod) {
	    return 8;
	}

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final DATA other = (DATA) obj;
            if (this.value != other.value) {
                return false;
            }
            if (Float.floatToIntBits(this.weight) != Float.floatToIntBits(other.weight)) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 59 * hash + this.value;
            hash = 59 * hash + Float.floatToIntBits(this.weight);
            return hash;
        }

        @Override
        public SubRecord merge(SubRecord no, SubRecord bo) {
            DATA d = this;
            if (!(no == null && bo == null && (no instanceof DATA) && (bo instanceof DATA))) {
                final DATA nd = (DATA) no;
                final DATA bd = (DATA) bo;
                SkyBash.merge(d.value, nd.value, bd.value, type[0], "value");
                SkyBash.merge(d.weight, nd.weight, bd.weight, type[0], "weight");
            }
            return d;
        }
    }

    class ENIT extends SubRecord {

	int baseCost = 0;
	LFlags flags = new LFlags(4);

	ENIT () {
	    super(Type.ENIT);
	}

	@Override
	void export(LExporter out, Mod srcMod) throws IOException {
	    super.export(out, srcMod);
	    out.write(baseCost);
	    out.write(flags.export(),4);
	}

	@Override
	void parseData(LStream in) throws BadRecord, DataFormatException, BadParameter, IOException {
	    super.parseData(in);
	    baseCost = in.extractInt(4);
	    flags.set(in.extract(4));
	    if (SPGlobal.logging()) {
		logSync("", "Base cost: " + baseCost + ", flags: " + flags);
	    }
	}

	@Override
	SubRecord getNew(Type type) {
	    return new ENIT();
	}

	@Override
	int getContentLength(Mod srcMod) {
	    return 8;
	}

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final ENIT other = (ENIT) obj;
            if (this.baseCost != other.baseCost) {
                return false;
            }
            if (!Objects.equals(this.flags, other.flags)) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 3;
            hash = 67 * hash + this.baseCost;
            hash = 67 * hash + Objects.hashCode(this.flags);
            return hash;
        }

        @Override
        public SubRecord merge(SubRecord no, SubRecord bo) {
            ENIT e = this;
            if (!(no == null && bo == null && (no instanceof ENIT) && (bo instanceof ENIT))) {
                final ENIT ne = (ENIT) no;
                final ENIT be = (ENIT) bo;
                SkyBash.merge(e.baseCost, ne.baseCost, be.baseCost, type[0], "base cost");
                e.flags.merge(ne.flags, be.flags, type[0]);
            }
            return e;
        }
    }

    /**
     *
     */
    public enum INGRFlag {
	/**
	 *
	 */
	ManualCalc(0),
	/**
	 *
	 */
	Food(1),
	/**
	 *
	 */
	ReferencesPersist(8)
	;

	int value;

	INGRFlag (int value) {
	    this.value = value;
	}
    }

    /*
     * SkyBash Functions.
     */
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final INGR other = (INGR) obj;
        if (!Arrays.deepEquals(this.types, other.types)) {
            return false;
        }
        if (!Objects.equals(this.MODL, other.MODL)) {
            return false;
        }
        if (!Objects.equals(this.MODT, other.MODT)) {
            return false;
        }
        if (!Objects.equals(this.YNAM, other.YNAM)) {
            return false;
        }
        if (!Objects.equals(this.ZNAM, other.ZNAM)) {
            return false;
        }
        if (!Objects.equals(this.DATA, other.DATA)) {
            return false;
        }
        if (!Objects.equals(this.ENIT, other.ENIT)) {
            return false;
        }
        if (!Objects.equals(this.ICON, other.ICON)) {
            return false;
        }
        if (!Objects.equals(this.MICO, other.MICO)) {
            return false;
        }
        if (!Objects.equals(this.ETYP, other.ETYP)) {
            return false;
        }
        if (!Objects.equals(this.scripts, other.scripts)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 41 * hash + Arrays.deepHashCode(this.types);
        hash = 41 * hash + Objects.hashCode(this.MODL);
        hash = 41 * hash + Objects.hashCode(this.MODT);
        hash = 41 * hash + Objects.hashCode(this.YNAM);
        hash = 41 * hash + Objects.hashCode(this.ZNAM);
        hash = 41 * hash + Objects.hashCode(this.DATA);
        hash = 41 * hash + Objects.hashCode(this.ENIT);
        hash = 41 * hash + Objects.hashCode(this.ICON);
        hash = 41 * hash + Objects.hashCode(this.MICO);
        hash = 41 * hash + Objects.hashCode(this.ETYP);
        hash = 41 * hash + Objects.hashCode(this.scripts);
        return hash;
    }

    @Override
    public MajorRecord merge(MajorRecord no, MajorRecord bo) {
        super.merge(no, bo);
        INGR i = this;
        if (!(no == null && bo == null && (no instanceof INGR) && (bo instanceof INGR))) {
            final INGR ni = (INGR) no;
            final INGR bi = (INGR) bo;
            SubRecords sList = i.subRecords;
            SubRecords nsList = ni.subRecords;
            SubRecords bsList = bi.subRecords;
            for (SubRecord s : sList) {
                s.merge(nsList.get(s.type[0]), bsList.get(s.type[0]));
            }
        }
        return i;
    }
    
    // Get/set
    /**
     *
     * @param groundModel
     */
    public void setModel (String groundModel) {
	MODL.setString(groundModel);
    }

    /**
     *
     * @return
     */
    public String getModel () {
	return MODL.string;
    }

    /**
     *
     * @param pickupSound
     */
    public void setPickupSound (FormID pickupSound) {
	YNAM.setForm(pickupSound);
    }

    /**
     *
     * @return
     */
    public FormID getPickupSound () {
	return YNAM.getForm();
    }

    /**
     *
     * @param dropSound
     */
    public void setDropSound (FormID dropSound) {
	ZNAM.setForm(dropSound);
    }

    /**
     *
     * @return
     */
    public FormID getDropSound () {
	return ZNAM.getForm();
    }

    /**
     *
     * @param weight
     */
    public void setWeight (float weight) {
	DATA.weight = weight;
    }

    /**
     *
     * @return
     */
    public float getWeight() {
	return DATA.weight;
    }

    public int getValue() {
	return DATA.value;
    }

    public void setValue (int value) {
	DATA.value = value;
    }

    /**
     *
     * @param baseCost
     */
    public void setBaseCost (int baseCost) {
	ENIT.baseCost = baseCost;
    }

    /**
     *
     * @return
     */
    public int getBaseCost () {
	return ENIT.baseCost;
    }

    /**
     *
     * @param flag
     * @param on
     */
    public void set (INGRFlag flag, boolean on) {
	ENIT.flags.set(flag.value, on);
    }

    /**
     *
     * @param flag
     * @return
     */
    public boolean get (INGRFlag flag) {
	return ENIT.flags.get(flag.value);
    }

    /**
     *
     * @param filename
     */
    public void setInventoryIcon (String filename) {
	ICON.setString(filename);
    }

    /**
     *
     * @return
     */
    public String getInventoryIcon () {
	return ICON.print();
    }

    /**
     *
     * @param filename
     */
    public void setMessageIcon (String filename) {
	MICO.setString(filename);
    }

    /**
     *
     * @return
     */
    public String getMessageIcon () {
	return MICO.print();
    }

    /**
     *
     * @param equipType
     */
    public void setEquipType (FormID equipType) {
	ETYP.setForm(equipType);
    }

    /**
     *
     * @return
     */
    public FormID getEquipType () {
	return ETYP.getForm();
    }
}
